/**
 * 
 */
package pruebas.VerduleriaOl.dominio.entidades;

import java.util.Collections;
import java.util.Map;

import javax.enterprise.context.Dependent;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.persistence.Transient;

import pruebas.VerduleriaOl.calificadores.Eventos.Agregado;
import pruebas.VerduleriaOl.calificadores.Eventos.Modificado;
import pruebas.VerduleriaOl.calificadores.Eventos.Quitado;
import pruebas.VerduleriaOl.dominio.incrustables.ItemCarrito;

import com.intelap.fabricaciones.Entidad;
import com.intelap.utils.ProductorRecursos;

/** @author ggpollit */
public abstract class Carrito extends Entidad<Carrito> {

	//// Propiedades persistentes ////

	protected abstract Map<? extends TipoArticulo, ItemCarrito> getItems();
	protected abstract void agregarItem(TipoArticulo tipoArticulo, ItemCarrito item);
	protected abstract ItemCarrito quitarItem(TipoArticulo tipoArticulo);


	//// Propiedades transitorias ////

	//// Constructores ////

	protected Carrito() {
		super(Carrito.class);
	}


	//// Comportamiento //// 

	@Transient
	public Map<TipoArticulo, ItemCarrito> getItems_const() {
		return Collections.unmodifiableMap(this.getItems());
	}

	/** Pone en este carrito la cantidad recibida de articulos del tipo recibido.
	 * Da la cantidad de articulos del tipo recibido que tendrá el carrito al terminar esta operacion.
	 * La cantidad efectivamente agregada puede diferir de la cantidad se intente agregar cuando 'cantidadSeIntentaAgregar' es negativa. */
	public int ponerArticulos(TipoArticulo tipoArticulo, int cantidadSeIntentaAgregar) {
		if( cantidadSeIntentaAgregar == 0) {
			ItemCarrito item = this.getItems().get(tipoArticulo);
			return item != null ? item.getCantidad() : 0;
		}
		
		ItemCarrito itemQuitado = this.getItems().remove(tipoArticulo);
		int cantidadFinal = cantidadSeIntentaAgregar + (itemQuitado != null ? itemQuitado.getCantidad() : 0);
		if( cantidadFinal > 0 ) {
			ItemCarrito nuevoItem = new ItemCarrito(cantidadFinal);
			this.agregarItem(tipoArticulo, nuevoItem);
			if( itemQuitado != null)
				this.getDelegado().anunciarItemReemplazado(tipoArticulo, itemQuitado, nuevoItem);
			else
				this.getDelegado().anunciarItemAgregado(tipoArticulo, nuevoItem);
		} else {
			this.getDelegado().anunciarItemQuitado(tipoArticulo, itemQuitado);
			cantidadFinal = 0;
		}
		return cantidadFinal;
	}

	/** Intenta sacar de este carrito la cantidad recibida de articulos del tipo recibido
	 * Da la cantidad de articulos que se pudieron sacar. */
	public int sacarArticulos(TipoArticulo tipoArticulo, int cantidadSeIntentaSacar) {
		ItemCarrito item = this.getItems().get(tipoArticulo);
		int cantidadExistente = item != null ? item.getCantidad() : 0;
		int cantidadRemanente = ponerArticulos(tipoArticulo, -cantidadSeIntentaSacar);
		return cantidadExistente - cantidadRemanente;
	}


	//// Delegado manejado ////

	private transient DelegadoCarrito delegado;
	private DelegadoCarrito getDelegado() {
		if (delegado == null)
			delegado = ProductorRecursos.getManagedBeanEstricto(this, DelegadoCarrito.class);
		return delegado;
	}

	@Dependent
	public static class DelegadoCarrito {
		@Inject
		@Agregado
		private Event<EventoCarrito> lanzadorEventosItemAgregado;
		void anunciarItemAgregado(TipoArticulo tipoArticulo, ItemCarrito itemAgregado) {
			lanzadorEventosItemAgregado.fire(new EventoCarrito(tipoArticulo, itemAgregado));
		}

		public void anunciarItemReemplazado(TipoArticulo tipoArticulo, ItemCarrito itemQuitado, ItemCarrito nuevoItem) {
			// TODO Auto-generated method stub

		}

		@Inject
		@Quitado
		private Event<EventoCarrito> lanzadorEventosItemQuitado;
		void anunciarItemQuitado(TipoArticulo tipoArticulo, ItemCarrito itemQuitado) {
			lanzadorEventosItemQuitado.fire(new EventoCarrito(tipoArticulo, itemQuitado));
		}

		@Inject
		@Modificado
		private Event<EventoCarrito> lanzadorEventosItemModificado;
		void anunciarItemModificado(TipoArticulo tipoArticulo, ItemCarrito itemModificado) {
			lanzadorEventosItemModificado.fire(new EventoCarrito(tipoArticulo, itemModificado));
		}
	}

	public static class EventoCarrito {
		public final TipoArticulo tipoArticulo;
		public final ItemCarrito itemCarrito;
		EventoCarrito(TipoArticulo tipoArticulo, ItemCarrito itemCarrito) {
			this.tipoArticulo = tipoArticulo;
			this.itemCarrito = itemCarrito;
		}
	}
}
